grammar LDD;

options {
    output = AST;
    k = 1;
}

tokens {
	DISTRIBUTION;
	DISTRIBUTION_ID;
	STATEMENT;
	IFSTATEMENT;
	EXPRESSION;
	DEFINITION;
	PAREN;
	BLOCK;
	ARGS;
	CONDITION;
	FUNCTION_CALL;
	ARRAY_ACCESS;
	IDENTIFIER; 
	INDEX;
	ARRAY_VALUE;
	PARENTS;
	DOMAIN;
	DEFINITION;
	IF;
	ASSIGNMENT;
	RETURN;
}

@header {
       package com.gr.experimental.antlr;
}
   
@lexer::header {
       package com.gr.experimental.antlr;
   }
  
@members {
    protected void mismatch( IntStream input, int tokenType, BitSet follow ) throws RecognitionException {
        throw new MismatchedTokenException( tokenType, input );
    }
    
    public void recoverFromMismatchedSet( IntStream input, RecognitionException ex, BitSet follow )
        throws RecognitionException {
        
        throw ex;
    }
}

@rulecatch {
    catch ( RecognitionException ex ) {
        throw ex;
    }
}

distribution
	: 'distribution' ( Identifier )? 
	 parentsDeclaration ?
	 domainDeclaration
	 distributionDefinition -> 
	 	^(DISTRIBUTION 
	 		^(DISTRIBUTION_ID Identifier?) 
	 		^(PARENTS parentsDeclaration?)
			^(DOMAIN domainDeclaration)
	 		^(DEFINITION distributionDefinition)
	 	)
	;

parentsDeclaration
	:	'parents'! Identifier ( ','! Identifier ) *
	;
	
domainDeclaration
	:	'domain'! LBRACKET! entityIdentifier ( ','! entityIdentifier ) * RBRACKET!
	;

distributionDefinition
	:	
//		LBRACE!
//		ifelsestatement*
//		RBRACE!
		block
	;

ifelsestatement
	:	'if' condition block ('else' elsestatement)? -> ^(IF condition block elsestatement?)
	;
	
elsestatement
	: ifelsestatement
	| block 
	;

condition
	:	parExpression -> ^(CONDITION parExpression)
	;

block
	:	LBRACE statement* RBRACE -> ^(BLOCK statement*)
	;
	
statement
	:	ifelsestatement 
	|	block
 	| 	returnStatement
	|	assignable '=' expression';'-> ^(ASSIGNMENT assignable expression)
	;


returnStatement
	:	'return'
		( SEMI -> RETURN
		| arrayValue SEMI -> ^(RETURN arrayValue)
//		| Identifier SEMI -> ^(RETURN Identifier)
		)
	;




assignable
	:	Identifier 
		(arrayIndex -> ^(ARRAY_ACCESS ^(IDENTIFIER Identifier) arrayIndex)
		| -> ^(IDENTIFIER Identifier (Identifier)*)
		)

	;

parExpression
	:	LPAREN! expression RPAREN!
	;

expression
	:	conditionalExpression
	;

expressionList
    :   expression ( COMMA! expression)*
    ;
    
assignmentOperator
    :	BECOMES
    |   BECOMES_PLUS
    |   BECOMES_MINUS
    |   BECOMES_TIMES
    |   BECOMES_DIV
    |   BECOMES_REST
	;
	
conditionalExpression
    :   conditionalOrExpression 
	;

conditionalOrExpression
    :   conditionalAndExpression ( OR! conditionalAndExpression )*
	;
	
conditionalAndExpression
    :   equalityExpression ( AND^ equalityExpression )*
	;
	
equalityExpression
    :   relationalExpression ( ( EQUALS^ | NOT_EQUALS^ ) relationalExpression )*
	;		

relationalExpression 
	:	additiveExpression 	( relationalOp^ additiveExpression )*
	;

relationalOp
	:	( LT^ | GT^ | LTE^ | GTE^ )
	;	
	
additiveExpression
    :   multiplicativeExpression ( (PLUS^ | MINUS^) multiplicativeExpression )*
	;
		
multiplicativeExpression
    :   unaryExpression ( ( TIMES^ | DIV^ | REST^ ) unaryExpression )*
	;

unaryExpression
    :   PLUS^ unaryExpression
    |	MINUS^ unaryExpression
    |   unaryExpressionNotPlusMinus
    ;

unaryExpressionNotPlusMinus
    :   '!'^ unaryExpression
    |   primary //selector* 
    ;


arguments
	:	LPAREN expressionList? RPAREN -> ^(ARGS expressionList)
	;
		
primary
	:	parExpression
	|	literal
	|   	Identifier 
		( arguments -> ^(FUNCTION_CALL ^(IDENTIFIER Identifier) arguments)
		| arrayIndex -> ^(ARRAY_ACCESS 	^(IDENTIFIER Identifier) arrayIndex)
		| (DOT Identifier)* -> ^(IDENTIFIER Identifier (Identifier)*)
		)
	;

arrayValue
	:	'[' (expression (',' expression )*)? ']' -> ^(ARRAY_VALUE expression expression* )
	;

arrayIndex
	:	LBRACKET expression RBRACKET -> expression
	;	
	
literal	
	:   integerLiteral
    |   FloatingPointLiteral
    |   booleanLiteral
	;  
  
integerLiteral 	
	: DecimalLiteral
	;
	
entityIdentifier
	:	booleanLiteral
	|	Identifier
	; 
  
booleanLiteral
    : TRUE
    | FALSE
    | ABSURD
    ;

// LEXER

//keywords
TRUE
	: 'true'
	;
	
FALSE
	: 'false'
	;

ABSURD
	: 'absurd'
	;

//operators
AND
	: '&&'
	;
OR
	: '||'
	;

DOT
	: '.'
	;
	
BECOMES    
	: '='
	;
	
COLON
	: ':'
	;
	
SEMI
	: ';'
	;
	
COMMA
	: ','
	;
	
LBRACE		
	: '{'
	;
	
RBRACE
	: '}'
	;
	
LBRACKET
	: '['
	;
	
RBRACKET
	: ']'
	;
	
LPAREN
	: '('
	;
	
RPAREN
	: ')'
	;
	
EQUALS
	: '=='
	;
	
NOT_EQUALS
	: '!='
	;

NOT
	: '!'
	;

LT
	: '<'
	;
	
LTE
	: '<='
	;
	
GT
	: '>' 
	;
	
GTE
	: '>='
	;
	
INC
	: '++'
	;
	
DEC
	: '--'
	;
	
PLUS
	: '+'
	;
	
MINUS
	: '-'
	;
	
TIMES
	: '*'
	;
	
DIV
	: '/'
	;
	
REST
	: '%'
	;

BECOMES_PLUS
	: '+='
	;

BECOMES_MINUS
	: '-='
	;

BECOMES_TIMES
	: '*='
	;

BECOMES_DIV
	: '/='
	;

BECOMES_REST
	: '%='
	;


DecimalLiteral : ('0' | '1'..'9' '0'..'9'*);

FloatingPointLiteral
    :   ('0'..'9')+ '.' ('0'..'9')* Exponent? 
    |   '.' ('0'..'9')+ Exponent? 
    |   ('0'..'9')+ Exponent 
	;

fragment
Exponent : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

Identifier 
    :   Letter (Letter|JavaIDDigit)*
    ;

fragment
Letter
    :  '\u0024' |
       '\u0041'..'\u005a' |
       '\u005f' |
       '\u0061'..'\u007a' |
       '\u00c0'..'\u00d6' |
       '\u00d8'..'\u00f6' |
       '\u00f8'..'\u00ff' |
       '\u0100'..'\u1fff' |
       '\u3040'..'\u318f' |
       '\u3300'..'\u337f' |
       '\u3400'..'\u3d2d' |
       '\u4e00'..'\u9fff' |
       '\uf900'..'\ufaff'
    ;

fragment
JavaIDDigit
    :  '\u0030'..'\u0039' |
       '\u0660'..'\u0669' |
       '\u06f0'..'\u06f9' |
       '\u0966'..'\u096f' |
       '\u09e6'..'\u09ef' |
       '\u0a66'..'\u0a6f' |
       '\u0ae6'..'\u0aef' |
       '\u0b66'..'\u0b6f' |
       '\u0be7'..'\u0bef' |
       '\u0c66'..'\u0c6f' |
       '\u0ce6'..'\u0cef' |
       '\u0d66'..'\u0d6f' |
       '\u0e50'..'\u0e59' |
       '\u0ed0'..'\u0ed9' |
       '\u1040'..'\u1049'
   ;

WS  :  (' '|'\r'| '\f' |'\t'|'\n') {$channel=HIDDEN;}
    ;



COMMENT
    :   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

LINE_COMMENT
    : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    ;


